import tkinter as tk
import random
import math
import tkinter.font as tkfont
import os
import winsound
import threading

# 延迟导入 vlc（按需加载），避免在未安装时在静态分析阶段报错
vlc = None
VLC_AVAILABLE = False

# VLC 播放器实例（按需创建）
vlc_player = None
# 后备播放线程（当没有 VLC 可用时使用 playsound 回退）
music_thread = None
music_stop_event = None
messages = [
    "多喝水哦~",
    "保持微笑呀՞˶･֊･˶՞",
    "每天都要元气满满",
    "记得吃水果",
    "保持好心情⊹꙳ ˶˙ᵕ˙˶ ⊹꙳",
    "好好爱自己₍ᐢ·ᴗ·ᐢ₎",
    "我想你了",
    "期待下一次见面",
    "金榜题名",
    "顺顺利利੭ ˙ᗜ˙ ੭",
    "早点休息(｡•o•｡∩)",
    "愿所有烦恼都消失 ˃̶͈ ꇴ ˂̶͈ ",
    "别熬夜，今天过得开心嘛๑>ᴗO๑",
    "天冷了，多穿衣服",
    "今天天气怎么样",
    "今天的你也很辛苦",
    "期待我们下次见面>ᴗoಣ",
    "在干嘛呢",
    "别熬夜",
    "愿所有梦想成真",
    "好好吃饭 ʕÖʕÖʔ ",
    "旦逢良辰，顺颂时宜",
    "见到你就很开心✌︎˶╹ꇴ╹˶✌︎",
    "你笑起来真好看 ˋˏᰔᩚˎˊ˗",
    "告诉你，我在想你",
    "时间都很珍贵",
    "你是今天的小幸运",
    "有好多事想对你说",
    "有你在就很安心✌︎' ֊'",
    "你的努力很有用ദ്ദി˶ｰ̀֊ｰ́ )✧",
    "一切都会变好୧( ⁼̴̶̤̀ω⁼̴̶̤́ )૭",
    "慢慢来ദ്ദി˶˃ ᵕ < )✧",
    "今天也为你加油",
    "你已经很棒了",
    "小挫折而已",
    "累了就停下来",
    "你的坚持，终有所得^ω^ ",
    "每天进步一点点",
    "你值得温柔对待(´ฅ•ω•ฅ`)"
]
bg_colors = ["#F690A1", "#6AB6CF", "#76F076", "#EEEE7D", "#F78798", "#83F2F2"]
def create_popup():
    msg = random.choice(messages)
    bg_color = random.choice(bg_colors)
    font_size = random.randint(13, 13)
    
    popup = tk.Toplevel(root)
    popup.title("つ♡⊂")
    popup.configure(bg=bg_color)

    # 屏幕尺寸
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()

    # 文字字体测量和换行处理
    padding = 63  # 考虑内边距和边框
    max_popup_width = int(screen_width * 1)  # 限制单个弹窗最大宽度为屏幕的 50%

    # 先创建一个字体对象用于测量；如必要，逐步减小字体以保证单词不被截断
    font_size_candidate = font_size
    while True:
        font_obj = tkfont.Font(family="Arial", size=font_size_candidate)
        # 测量最长的单词，避免换行把单词切断
        words = msg.split()
        if not words:
            longest_word_width = 0
        else:
            longest_word_width = max(font_obj.measure(w) for w in words)

        # 如果最长单词太宽，尝试缩小字体直到可容纳或到达最小字体限制
        if longest_word_width + padding <= max_popup_width or font_size_candidate <= 7:
            break
        font_size_candidate -= 1

    # 计算整体文本宽度并确保最长单词可见
    text_width = font_obj.measure(msg)
    screen_margin = 50

    # 如果最长单词在最小字体下仍然超过 max_popup_width，则扩大弹窗以容纳最长单词（但不超出屏幕）
    if longest_word_width + padding > max_popup_width:
        popup_width = min(longest_word_width + padding, screen_width - screen_margin)
        wrap_len = popup_width - padding
    else:
        if text_width + padding > max_popup_width:
            popup_width = max_popup_width
            wrap_len = popup_width - padding
        else:
            popup_width = text_width + padding
            wrap_len = popup_width - padding

    # 先隐藏窗口以测量真实高度（使用 wraplength）
    popup.withdraw()
    label = tk.Label(popup, text=msg, bg=bg_color, font=("Arial", font_size_candidate), wraplength=wrap_len, justify='center')
    label.pack(expand=True, fill='both', padx=10, pady=10)
    popup.update_idletasks()

    req_w = label.winfo_reqwidth()
    req_h = label.winfo_reqheight()

    # 如果测量宽度仍然超过屏幕可用宽度，重新设置 wraplength 并重测
    if req_w > screen_width - screen_margin:
        popup_width = screen_width - screen_margin
        wrap_len = popup_width - padding
        label.config(wraplength=wrap_len)
        popup.update_idletasks()
        req_w = label.winfo_reqwidth()
        req_h = label.winfo_reqheight()

    popup_width = req_w
    popup_height = req_h

    # 估算窗口装饰（标题栏等）高度，防止垂直方向被遮挡
    titlebar_estimate = 30  # Windows 下常见标题栏与边框高度估算
    outer_popup_height = popup_height + titlebar_estimate

    # 心形参数方程（经典心形）
    def heart_point(t):
        x = 16 * math.sin(t) ** 3
        y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)
        return x, y

    # 根据当前弹窗序号在心形上取点
    try:
        t = (popup_count / MAX_POPUPS) * 2 * math.pi
    except Exception:
        t = 0.0

    hx, hy = heart_point(t)

    # 缩放与中心
    scale = min(screen_width, screen_height) / 40
    center_x = screen_width // 2
    center_y = int(screen_height * 0.45)  # 稍微偏上，使心形更居中视觉

    x = int(center_x + hx * scale - popup_width / 2)
    # 注意：心形方程的 y 趋势与屏幕坐标相反，因此取反
    y = int(center_y - hy * scale - popup_height / 2)

    # 保证弹窗完全位于屏幕内（考虑标题栏/装饰高度）
    vertical_margin = 20
    x = max(0 + vertical_margin, min(x, screen_width - popup_width - vertical_margin))
    y = max(0 + vertical_margin, min(y, screen_height - outer_popup_height - vertical_margin))

    # 使用 outer_popup_height 保证窗口在垂直方向有足够空间
    popup.geometry(f"{popup_width}x{outer_popup_height}+{x}+{y}")
    popup.deiconify()
    popup.resizable(False, False)


# --- main application ---
root = tk.Tk()
root.title("Popup Demo")
root.geometry("320x160")

# 音乐播放设置（仅支持 WAV 文件，Windows 下）
# 将 MUSIC_FILE 设置为你本地的 wav 文件路径，例如 r"E:\练习\music.wav"
MUSIC_FILE = r"C:\Users\T-T\Downloads\晚风.mp3"  # 如果为空则不播放音乐；若设置请使用原始字符串，例如 r"E:\\练习\\music.mp4"

def start_music():
    """开始循环播放 MUSIC_FILE（如果存在且为 wav）。"""
    if not MUSIC_FILE:
        print("MUSIC_FILE 未设置，跳过播放音乐。")
        return
    if not os.path.isfile(MUSIC_FILE):
        print(f"音乐文件不存在：{MUSIC_FILE}，跳过播放音乐。")
        return
    ext = os.path.splitext(MUSIC_FILE)[1].lower()
    try:
        if ext == '.wav':
            # 循环异步播放 WAV（Windows winsound）
            winsound.PlaySound(MUSIC_FILE, winsound.SND_FILENAME | winsound.SND_ASYNC | winsound.SND_LOOP)
            print(f"开始播放 WAV 音乐：{MUSIC_FILE}")
        else:
            # 按需导入 python-vlc，以避免在未安装时在静态分析或启动时直接报错
            global vlc, VLC_AVAILABLE, vlc_player, music_thread, music_stop_event
            if not VLC_AVAILABLE:
                try:
                    import vlc as _vlc
                    vlc = _vlc
                    VLC_AVAILABLE = True
                except Exception:
                    VLC_AVAILABLE = False

            if VLC_AVAILABLE:
                # 使用 VLC 播放并尝试设置循环
                try:
                    instance = vlc.Instance()
                    media = instance.media_new(MUSIC_FILE)
                    # 尝试设置无限循环选项（不同版本可能支持或忽略）
                    try:
                        media.add_option('input-repeat=-1')
                    except Exception:
                        pass
                    vlc_player = instance.media_player_new()
                    vlc_player.set_media(media)
                    vlc_player.play()
                    print(f"开始使用 VLC 播放：{MUSIC_FILE}")
                    return
                except Exception as e:
                    print(f"使用 VLC 播放失败：{e}")

            # 回退到 playsound（如果可用）——在后台线程循环播放以避免阻塞主线程
            try:
                from playsound import playsound as _playsound
            except Exception:
                print(f"要播放非 WAV 文件（{ext}）需要安装 python-vlc 或 playsound；当前都不可用，跳过播放。")
                return

            def _play_loop(stop_event):
                try:
                    while not stop_event.is_set():
                        _playsound(MUSIC_FILE)
                        # playsound 是阻塞的，循环会在文件播放完后继续
                except Exception as e:
                    print(f"后台播放线程出错：{e}")

            music_stop_event = threading.Event()
            music_thread = threading.Thread(target=_play_loop, args=(music_stop_event,), daemon=True)
            music_thread.start()
            print(f"使用 playsound 后备播放：{MUSIC_FILE}")
    except Exception as e:
        print(f"播放音乐失败：{e}")

def stop_music():
    """停止播放音乐。"""
    try:
        # 停止 winsound（如果在播放 WAV）
        winsound.PlaySound(None, winsound.SND_PURGE)
    except Exception:
        pass
    try:
        global vlc_player
        if VLC_AVAILABLE and vlc_player is not None:
            vlc_player.stop()
            try:
                vlc_player.release()
            except Exception:
                pass
            vlc_player = None
        print("已停止音乐播放。")
    except Exception as e:
        print(f"停止音乐失败：{e}")
    # 停止后台 playsound 线程（如果有）
    try:
        global music_stop_event, music_thread
        if music_stop_event is not None:
            music_stop_event.set()
        if music_thread is not None and music_thread.is_alive():
            music_thread.join(timeout=1.0)
        music_thread = None
        music_stop_event = None
    except Exception:
        pass

# 自动弹出设置（毫秒）
POPUP_INTERVAL_MS = 100  # 每0.1秒弹出一次，可按需修改

# 自动停止设置
MAX_POPUPS = 160  # 达到此次数后停止自动弹窗
popup_count = 0

def start_auto_popups():
    """生成一个弹窗并在间隔后再次调用自身以实现循环自动弹窗。

    当达到 MAX_POPUPS 时，停止调度并在短延迟后关闭主窗口。
    """
    global popup_count
    if popup_count >= MAX_POPUPS:
        print(f"已达到 {MAX_POPUPS} 次弹窗，程序将在短暂延迟后关闭。")
        # 给最后的弹窗一点时间后关闭主窗口
        # 停止音乐（如果在播放）
        stop_music()
        root.after(500, root.destroy)
        return

    create_popup()
    popup_count += 1
    root.after(POPUP_INTERVAL_MS, start_auto_popups)

def begin_sequence():
    """在启动时先播放音乐（如配置），然后开始自动弹窗序列。"""
    start_music()
    start_auto_popups()

# 延迟启动：程序启动0.1秒后开始自动弹窗并播放音乐
root.after(100, begin_sequence)

root.mainloop()